﻿using System.Collections.Generic;
using Amazon.SQS;
using Amazon.SQS.Model;
using NUnit.Framework;
using Rhino.Mocks;
using ShuttleBus;
using ShuttleBus.Transports.AmazonSqs;
using Attribute = Amazon.SQS.Model.Attribute;
using Message = Amazon.SQS.Model.Message;

namespace Tests.Transports.AmazonSqs.SqsTests
{
    public partial class SqsTests
    {
        [TestFixture]
        public class WhenGettingMessageFromQueue
        {
            private Sqs _queue;
            private AmazonSQS _sqsClient;
            private IEndpoint _endpoint;

            [SetUp]
            public void SetUp()
            {
                _sqsClient = MockRepository.GenerateMock<AmazonSQS>();
                _endpoint = MockRepository.GenerateMock<IEndpoint>();
            }

            [TearDown]
            public void TearDown()
            {
                _sqsClient.VerifyAllExpectations();
            }

            [Test]
            public void QueueDoesNotHaveMessage()
            {
                var queueUrl = "url";
                var messageResponse = new ReceiveMessageResponse
                {
                    ReceiveMessageResult = new ReceiveMessageResult
                    {
                        Message = new List<Message>()
                    }
                };

                _endpoint.Stub(e => e.Path).Return(queueUrl);

                _queue = new Sqs(_sqsClient, _endpoint, 1);

                CreatesQueue(queueUrl);

                _sqsClient.Expect(
                    s => s.ReceiveMessage(Arg<ReceiveMessageRequest>.Matches(r => MatchesRequest(r, queueUrl, 1, 1))))
                    .Return(messageResponse);

                BaseMessage message;

                var result = _queue.HasMessage(out message);

                Assert.IsNull(message);
                Assert.IsFalse(result);

            }

            [Test]
            public void QueueHasMessage()
            {
                var queueUrl = "url";
                var messageResponse = new ReceiveMessageResponse
                {
                    ReceiveMessageResult = new ReceiveMessageResult
                    {
                        Message = new List<Message> { new Message { Body = "", Attribute = new List<Attribute> { new Attribute { Value = 12.ToString() } } } }
                    }
                };

                _endpoint.Stub(e => e.Path).Return(queueUrl);

                _queue = new Sqs(_sqsClient, _endpoint, 1);

                CreatesQueue(queueUrl);

                _sqsClient.Expect(
                    s => s.ReceiveMessage(Arg<ReceiveMessageRequest>.Matches(r => MatchesRequest(r, queueUrl, 1, 1))))
                    .Return(messageResponse);

                BaseMessage message;

                var result = _queue.HasMessage(out message);

                Assert.IsNotNull(message);
                Assert.IsAssignableFrom<SqsMessage>(message);
                Assert.IsTrue(result);

            }

            private bool MatchesRequest(ReceiveMessageRequest r, string url, int timeToProcess, int maxMessages)
            {
                return r.MaxNumberOfMessages == maxMessages && r.QueueUrl == url && r.VisibilityTimeout == timeToProcess;
            }


            private void CreatesQueue(string queueUrl)
            {
                var response = new CreateQueueResponse { CreateQueueResult = new CreateQueueResult { QueueUrl = queueUrl } };
                _sqsClient.Expect(s => s.CreateQueue(Arg<CreateQueueRequest>.Matches(r => QueueUrlsMatch(queueUrl, r)))).Return(
                    response);
                _sqsClient.Expect(
                    s => s.SetQueueAttributes(Arg<SetQueueAttributesRequest>.Matches(a => QueueAttributesMatch(a)))).
                    Return(new SetQueueAttributesResponse());
            }

            private static bool MessageMatches(string queueUrl, string message, SendMessageRequest m)
            {
                return m.MessageBody == message && m.QueueUrl == queueUrl;
            }

            private static bool QueueAttributesMatch(SetQueueAttributesRequest a)
            {
                return a.Attribute[0].Name == "MaximumMessageSize" && a.Attribute[0].Value == "65536";
            }

            private static bool QueueUrlsMatch(string queueName, CreateQueueRequest r)
            {
                return r.QueueName == queueName;
            }
        }
    }
}